﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using SimioAPI;
using SimioAPI.Extensions;
using System.Diagnostics;


namespace WLC
{
    public class WLCIntermediateProductStoreElementDefinition : IElementDefinition
    {
        #region IElementDefinition Members

        public IElement CreateElement(IElementData data)
        {
            return new WLCIntermediateProductStoreElement(data);
        }


        public void DefineSchema(IElementSchema schema)
        {
        }



        public string Name
        {
            get { return "WLCIntermediateProductStore"; }
        }

        public string Description
        {
            get { return ""; }
        }

        public System.Drawing.Image Icon
        {
            get { return null; }
        }


        public static readonly Guid ID = new Guid("{DA3B129C-1991-11DF-A5D5-B80156D89593}");

        public Guid UniqueID
        {
            get { return ID; }
        }

        #endregion
    }


    public class WLCIntermediateProductStoreElement : IElement
    {

        private Hashtable _store;
        public IElementData _data;
        public string NextOrderReservedFor { get; set; }

        public Hashtable Reservations { get; set; }

        public WLCIntermediateProductStoreElement(IElementData data)
        {
            Reservations = new Hashtable();
            _store = new Hashtable();
            _data = data;
            


            //System.IO.StreamWriter file = System.IO.File.CreateText("Log/Output.txt");

            //tr2 =  new TextWriterTraceListener(file);
            //Debug.Listeners.Add(tr2);

        }

        public bool CheckBOM(string orderID, WLCBOMElement bom, double orderSize)
        {
            _data.ExecutionContext.ExecutionInformation.TraceInformation("INTERMEDIATEPRODUCTSTORE: Checking bill of material for order " + orderID);

            Hashtable bomEntries = bom.getBOMEntries();

            Hashtable storageForID = (Hashtable)_store[orderID];
            double amountStored;
            double amountRequired;
            BOMEntry entry;

            if (bom == null)
            {

                return true;
            }

            // If BOM has not entries, return true
            if (((Hashtable)bom.getBOMEntries()).Count == 0)
            {
                _data.ExecutionContext.ExecutionInformation.TraceInformation("CHECKMATERIAL: " + orderID + " does not need any material.");
                return true;
            }

            if (storageForID == null)
            {

                _data.ExecutionContext.ExecutionInformation.TraceInformation("CHECKMATERIAL: No storage entry for " + orderID + ".");
                return false;
            }


            else
            {
                // Go through all entries in BOM
                foreach (string key in bomEntries.Keys)
                {
                    // Check if storage contains entry for BOM item
                    if (!storageForID.ContainsKey(key))
                    {
                        _data.ExecutionContext.ExecutionInformation.TraceInformation("CHECKMATERIAL: Item " + key + " not in stock for order  + " + orderID + ".");
                        return false;
                    }
                    else
                    {
                        entry = (BOMEntry)bomEntries[key];

                        // Check if amount stored is sufficient
                        amountStored = (double)storageForID[key];
                        amountRequired = entry.Amount * orderSize;

                        _data.ExecutionContext.ExecutionInformation.TraceInformation("CHECKMATERIAL: Amount stored of item " + key + " for order " + orderID + " is " + amountStored.ToString());

                        if (amountRequired > amountStored)
                        {
                            _data.ExecutionContext.ExecutionInformation.TraceInformation("CHECKMATERIAL: Amount of item " + key + " not sufficient for order " + orderID + " (" + amountStored.ToString() + ").");
                            return false;
                        }
                    }
                }

            }


            return true;
        }


        public int InStock(string productionOrderID, string intermediateProduct)
        {
            int inStock;
            Hashtable storage;

            if (_store.Contains(productionOrderID))
            {
                storage = (Hashtable)_store[productionOrderID];

            }
            else
            {
                return 0;
            }

            if (storage.Contains(intermediateProduct))
            {
                inStock = (int)storage[intermediateProduct];
                return inStock;
            }
            else
            {
                return 0;
            }


        }


        public void Store(string productionOrderID, string intermediateProduct, double amount)
        {

            double currentlyStored;
            Hashtable storage;

            _data.ExecutionContext.ExecutionInformation.TraceInformation("INTERMEDIATEPRODUCTSTORE: Trying to store " + amount + " of product " + intermediateProduct + " for order " + productionOrderID + ".");
            if (_store.Contains(productionOrderID))
            {
                _data.ExecutionContext.ExecutionInformation.TraceInformation("INTERMEDIATEPRODUCTSTORE: Storage for order " + productionOrderID + " already there.");
                storage = (Hashtable)_store[productionOrderID];

            }
            else
            {
                _data.ExecutionContext.ExecutionInformation.TraceInformation("INTERMEDIATEPRODUCTSTORE: Adding storage for order " + productionOrderID + ".");
                _store.Add(productionOrderID, new Hashtable());
                storage = (Hashtable)_store[productionOrderID];
            }

            if (storage.Contains(intermediateProduct))
            {
                _data.ExecutionContext.ExecutionInformation.TraceInformation("INTERMEDIATEPRODUCTSTORE: Adding " + amount + " of " + intermediateProduct + " for order " + productionOrderID + ".");
                currentlyStored = (double)storage[intermediateProduct];
                currentlyStored += amount;
                storage.Remove(intermediateProduct);
                storage.Add(intermediateProduct, currentlyStored);

            }
            else
            {
                _data.ExecutionContext.ExecutionInformation.TraceInformation("INTERMEDIATEPRODUCTSTORE: Initially storing " + amount + " of " + intermediateProduct + " for order " + productionOrderID + ".");
                storage.Add(intermediateProduct, amount);
            }

        }

        public double Withdraw(string productionOrderID, string intermediateProduct, double amount)
        {

            // Returns error code, if withdrawal fails (-1 = no entry for production order, -2 = no entry for intermediate good,
            // -3 = not enough stored, >= 0 The amount left of the intermediate product for this production order (not sensible though))





            double currentlyStored;
            Hashtable storage;
            if (_store.Contains(productionOrderID))
            {
                storage = (Hashtable)_store[productionOrderID];

            }
            else
            {
                return -1;
            }

            if (storage.Contains(intermediateProduct))
            {
                currentlyStored = (double)storage[intermediateProduct];
                currentlyStored -= amount;

                if (currentlyStored == 0)
                    storage.Remove(intermediateProduct);

                else if (currentlyStored > 0)
                {
                    storage.Remove(intermediateProduct);
                    storage.Add(intermediateProduct, currentlyStored);
                    return currentlyStored;
                }
                else if (currentlyStored < 0)
                {
                    return -3;
                }

            }

            else
            {
                return -2;
            }

            return 0;
        }



        #region IElement Members



        public void Initialize()
        {

        }

        public void Shutdown()
        {

        }

        #endregion
    }



}

